/*	--- 重定向 & 转发 ---

#	Redirect

【重定向】是指: 当【浏览器】请求【一个URL】时，【服务器】返回【一个重定向指令】，告诉【浏览器】地址已经变了，麻烦使用【新的URL】再重新发送【新请求】。

例如，我们已经编写了一个【能处理/hello的HelloServlet】，如果【收到的路径为/hi】，希望能【重定向到/hello】，可以再【编写一个RedirectServlet】： */
@WebServlet(urlPatterns = "/hi")
public class RedirectServlet extends HttpServlet {
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// 构造【重定向的path】
		String name = req.getParameter("name");

		String redirectToUrl = "/hello" + (name == null ? "" : "?name=" + name);

		// 发送【重定向的响应】
		resp.sendRedirect(redirectToUrl);
	}
}


/*
如果【浏览器】发送【GET /hi】请求，【RedirectServlet】将处理【此请求】。

由于【RedirectServlet】在【内部】又发送了【重定向响应】，因此，【浏览器】会收到【如下响应】：

	HTTP/1.1 302 Found
	Location: /hello


当【浏览器】收到【302响应】后，它会立刻根据【Location的指示】发送一个新的【GET /hello请求】，
【这个过程】就是【重定向】：

┌───────┐   GET /hi     ┌───────────────┐
│Browser│ ────────────> │RedirectServlet│
│       │ <──────────── │               │
└───────┘   302         └───────────────┘


┌───────┐  GET /hello   ┌───────────────┐
│Browser│ ────────────> │ HelloServlet  │
│       │ <──────────── │               │
└───────┘   200 <html>  └───────────────┘


观察【Chrome浏览器】的【网络请求】，可以看到【2次HTTP请求】：

并且【浏览器】的【地址栏路径】自动更新为【/hello】。

【重定向】有2种：
一种是【302响应】，称为【临时重定向】，
一种是【301响应】，称为【永久重定向】。

【两者的区别】是，如果【服务器】发送【301永久重定向响应】，【浏览器】会【缓存"/hi"到"/hello"这个重定向的关联】，

下次请求"/hi"的时候，【浏览器】就直接发送"/hello请求"了。

Q: 重定向有什么作用？
A: 【重定向的目的】是当【Web应用】升级后，如果【请求路径】发生了变化，可以将【原来的路径】重定向到【新路径】，从而避免【浏览器】请求【原路径】找不到【资源】。

【HttpServletResponse】提供了【快捷的redirect()方法】实现【302重定向】。

如果要实现【301永久重定向】，可以这么写： */
resp.setStatus(HttpServletResponse.SC_MOCED_PERMANENTLY); // 301
resp.setHeader("Location", "/hello");


/*==========================================================


#	Forward

【Forward】是指【内部转发】。

当【一个Servlet】处理【请求】的时候，它可以【决定】自己【不继续处理】，而是【转发】给【另一个Servlet处理】。

例如，我们已经编写了【一个 能处理/hello 的 HelloServlet】，继续编写【一个 能处理 /morning的ForwardServlet】： */
@WebServlet(urlPatterns = "/morning")
public class ForwardServlet extends HttpServlet {
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

		req.getRequestDispatcher("/hello").forward(req, resp);
	}
}


/*
【ForwardServlet】在收到【请求】后，它并【不自己】发送【响应】，

而是把【请求和响应】都【转发】给【路径为/hello的Servlet】，即【下面的代码】： */
req.getRequestDispatcher("/hello").forward(req, resp);


/*
【后续请求的处理】实际上是由【HelloServlet】完成的。

这种【处理方式】称为【转发】（Forward），我们用【流程图】画出来如下：

                          ┌────────────────────────┐
                          │      ┌───────────────┐ │
                          │ ────>│ForwardServlet │ │
┌───────┐  GET /morning   │      └───────────────┘ │
│Browser│ ──────────────> │              │         │
│       │ <────────────── │              ▼         │
└───────┘    200 <html>   │      ┌───────────────┐ │
                          │ <────│ HelloServlet  │ │
                          │      └───────────────┘ │
                          │       Web Server       │
                          └────────────────────────┘

【转发】和【重定向】的"区别"在于，【转发】是在【Web服务器】内部完成的，对【浏览器】来说，【浏览器】只【发出了一个HTTP请求】

注意到【使用转发】的时候，【浏览器的地址栏】路径仍然是"/morning"，【浏览器】并不知道【该请求】在【Web服务器内部】实际上做了一次【转发】。


======================================================================


#	练习

使用【重定向】和【转发】 */




/*===================================================================


#	----- 重定向 & 转发 の 小结 -----

1. 使用【重定向】时，【浏览器】知道【重定向规则】，并且会【自动发起新的HTTP请求】；

2. 使用【转发】时，【浏览器】并不知道【服务器内部的转发逻辑】。


---------------------
汇总:
	1. 重定向 
	影响目标: Browser(浏览器)
		301 永久重定向(Client缓存)
		302 临时重定向(仅一次) 

	2. 转发
	影响目标: Server(服务器)

【重定向】例子: /hi -> /hello + name==null? 重定向 发回给Browser */
@WebServlet(urlPatterns = "/hi")
public class RedirectServlet extends HttpServlet {
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

		String name = req.getParameter("name");
		String redirectToUrl = "/hello" + (name == null ? "" : "?name=" + name);

		resp.sendRedirect(redirectToUrl); // <--
	}
}


/*
【转发】例子: */
@WebServlet(urlPatterns = "/morning")
public class ForwardServlet extends HttpServlet {
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

		req.getRequestDispatcher("/hello").forward(req, resp); // <--
	}
}





























